# −*− coding: UTF−8 −*− 

import operator
import random
from datetime import datetime

# Mapping der Aufgabenkürzel auf ihre Funktionen
operationen = {'a': operator.add,
               's': operator.sub,
               'm': operator.mul,
               'd': operator.truediv,
               }

# Mapping der Aufgabenkürzel auf ihre Operatoren
operatoren = {'a': '+',
              's': '-',
              'm': '*',
              'd': '/',
              }

# Mapping zur Definition der Schwierigkeitsgrade für die
# verschiedenen Aufgabentypen
schwierigkeit = {'l': {'a': [1, 50],   # leicht
                       's': [1, 50],
                       'm': [1, 5],
                       'd': [2, 5],
                       },
                 'm': {'a': [0, 100],  # mittel
                       's': [0, 100],
                       'm': [0, 10],
                       'd': [2, 10],
                       },
                 's': {'a': [30, 150], # schwer
                       's': [30, 150],
                       'm': [3, 12],
                       'd': [3, 12],
                       },
                 }

# Definition der Notenskala
notenskala = ((90, 'sehr gut'),
              (80, 'gut'),
              (70, 'befriedigend'),
              (50, 'ausreichend'),
              (30, 'mangelhaft'),
              )

def aufgabe(typ, grad):
    """Konstruiert eine Aufgabe vom Typ 'typ' und Schwierigkeitsgrad 'grad'.

    Unterstützte Typen sind: 
      'a': Addition
      's': Subtraktion
      'm': Multiplikation
      'd': Division

    Schwierigkeitsgrade sind leicht ('l'), mittel ('m') 
    und schwer ('s').

    Es wird erwartet, dass nur gültige Parameter übergeben
    werden, d.h. die Validierung der Benutzereingabe muss
    zuvor erfolgen.
      
    Liefert ein Tuple mit drei Zeichenketten zurück, 
    die die zugehörige Aufgabe darstellen: 
    (frage, ergebnis, antwortsatz)
    """
    vorschrift = operatoren[typ]
    operation = operationen[typ]
    minimum, maximum = schwierigkeit[grad][typ]

    z1 = random.randint(minimum, maximum)
    z2 = random.randint(minimum, maximum)

    # Bei leichten Subtraktionen soll z1 > z2 sein
    if typ == 's' and grad == 'l':
        z1, z2 = max(z1, z2), min(z1, z2)

    # Divisionen sollen immer ohne Rest aufgehen
    if typ =='d':
        z1 = z1*z2

    frage = "%s %s %s = " % (z1, vorschrift, z2)
    ergebnis = "%s" % int(operation(z1, z2))
    antwortsatz = frage + ergebnis

    return (frage, ergebnis, antwortsatz)
    

def auswahl():
    """Hilfsfunktion zur Abfrage des Aufgabentyps
    """
    eingabe = raw_input("\nAdditions- [A], Substraktions- [s], "\
                        "Multiplikations- [m] oder Divisionsaufgabe [d]? ")
    eingabe = eingabe.lower().strip()
    if eingabe not in ('s', 'm', 'd'):
        eingabe = 'a'
    return eingabe

def schwierigkeitsgrad():
    """Hilfsfunktion zur Abfrage des Schwierigkeitsgrades
    """
    wahl = raw_input("Leicht [l], mittel [M] oder schwer [s]? ")
    wahl = wahl.lower().strip()
    if wahl not in ['l', 'm', 's']:
        wahl = 'm'
    return wahl


def bewerte(r, f):
    """Hilfsfunktion zur Benotung des Schülers

    Eingabeparameter: r(ichtig), f(alsch)

    Berechnet den Prozentsatz der richtig gelösten Aufgaben
    und ermittelt daraus die Note mit Hilfe des 'notenskala'
    tuples.

    Gibt eine Zeichenkette mit dem Prädikat zurück.
    """
    prozent = float(r)*100/(r+f)
    for level, note in notenskala:
        if prozent >= level:
            return note
    return "Ungenügend"

def protokollant():
    """Öffnet eine Datei mit dem Namen den Benutzers
    und trägt einen Zeitstempel ein.
    Gibt das Fileobjekt zurück.
    """
    name = raw_input("Wie heisst Du? ")
    name = name.replace(' ', '').lower()
    filename = "%s.log" % name.title()
    protokoll = open(filename, 'a')
    protokoll.write(datetime.now().isoformat() + '\n')
    return protokoll

def trainer():
    """Hauptkontrollfunktion des Aufgabentrainers

    Enthält die zentrale Abfrageschleife und wertet
    die Benutzereingaben aus. 
    """
    fertig = False
    richtig = 0
    falsch = 0

    protokoll = protokollant()
    grad = schwierigkeitsgrad()

    while not fertig:
        typ = auswahl()
        frage, ergebnis, antwortsatz = aufgabe(typ, grad)

        antwort = raw_input("\n"+frage).strip()

        if antwort == ergebnis:
            richtig += 1
            print "\nRichtig! ", antwortsatz
        else:
            falsch += 1
            print "\nFalsch! ", antwortsatz
            
        protokoll.write("\nFrage: %s" % frage)
        protokoll.write("\nAntwort (Ergebnis): %s (%s)" % (antwort, ergebnis))
        protokoll.write("\nZwischenstand (richtig:falsch): %s : %s\n" % (richtig, falsch)) 
                        
        nochmal = raw_input("\nNochmal? (J/n)")
        if nochmal.lower() == 'n':
            fertig = True

    note = bewerte(richtig, falsch)
    resultat = "\n%s!\nDu hast %s Aufgaben richtig gelöst und %s Fehler gemacht." 
    print resultat % (note.title(), richtig, falsch)
    protokoll.write(resultat % (note.title(), richtig, falsch))
    protokoll.write("\n" + 60*'=' + "\n")
    protokoll.close()

if __name__ == "__main__":
    """Startet die Hauptkontrollfunktion 'trainer', wenn das Modul
    von der Kommandozeile aufgerufen wird.
    """
    trainer()
